use std::f32::consts::PI;

use ggez::{glam::Vec2,Context, graphics::{self, Rect}, mint::Point2};

use crate::particle_system;

pub struct Spaceship {
    location: Vec2,
    velocity: Vec2,
    acceleration: Vec2,
    topspeed: f32,

    a_location: f32,

    mass: f32,

    is_forced: bool,

    param: graphics::DrawParam,

    ps1: particle_system::PraticleSystem,
    ps2: particle_system::PraticleSystem
}

impl Spaceship {
    pub fn new() -> Spaceship {
        let location = Vec2{x: 400.0, y: 300.0};
        let velocity = Vec2{x: 0.0, y: 0.0};
        let acceleration = Vec2{x: 0.0, y: 0.0};
        let topspeed = 50.0;
        let a_location = 0.0;
        let mass = 10.0;
        let is_forced = false;
        let ps1 = particle_system::PraticleSystem::new(Vec2 { x: -5.0, y: 10.0 }, 0.0);
        let ps2 = particle_system::PraticleSystem::new(Vec2 { x: 5.0, y: 10.0 }, 0.0);
        let param = graphics::DrawParam::default();
        Spaceship { location, velocity, acceleration, topspeed, a_location, mass, is_forced, param, ps1, ps2}
    }

    fn limit(&mut self) -> () {
        if self.velocity.length() > self.topspeed {self.velocity = self.velocity.normalize()*self.topspeed};
    }

    fn check_edges(&mut self, ctx: &mut Context) -> () {
        if self.location.x > ctx.gfx.window().inner_size().width as f32 {
            self.location.x = ctx.gfx.window().inner_size().width as f32;
            self.velocity.x = -self.velocity.x;
        }
        else if self.location.x < 0.0{
            self.location.x = 0.0;
            self.velocity.x = -self.velocity.x;
        }
    
        if self.location.y > ctx.gfx.window().inner_size().height as f32 {
            self.location.y = ctx.gfx.window().inner_size().height as f32;
            self.velocity.y = -self.velocity.y;
        }
        else if self.location.y < 0.0 {
            self.location.y = 0.0;
            self.velocity.y = -self.velocity.y;
        }
    }

    fn apply_force(&mut self, force: Vec2) -> () {
        if !force.is_nan() {self.acceleration += force};
    }

    pub fn update(&mut self, ctx: &mut Context) -> () {
        if ctx.keyboard.is_key_pressed(ggez::winit::event::VirtualKeyCode::Left) {self.a_location -= 0.05};
        if ctx.keyboard.is_key_pressed(ggez::winit::event::VirtualKeyCode::Right) {self.a_location += 0.05};
        if ctx.keyboard.is_key_pressed(ggez::winit::event::VirtualKeyCode::Up) || ctx.keyboard.is_key_pressed(ggez::winit::event::VirtualKeyCode::Z) {
            let x = (self.a_location - PI/2.0).cos();
            let y = (self.a_location - PI/2.0).sin();
            let force = Vec2{x, y};
            self.apply_force(force*2.0);
            self.is_forced = true;
        } else {
            self.is_forced = false;
        }

        let force = -self.velocity.normalize()*self.velocity.length()*self.velocity.length()*0.05;
        self.apply_force(force);

        self.acceleration /= self.mass;
        self.velocity += self.acceleration;
        self.limit();
        self.location += self.velocity;

        self.acceleration *= 0.0;
        self.check_edges(ctx);

        self.param = graphics::DrawParam::default().dest(self.location).rotation(self.a_location);
        self.ps1.update(self.location, self.a_location);
        self.ps2.update(self.location, self.a_location);
    }

    pub fn display(&mut self, ctx: &mut Context, canvas : &mut graphics::Canvas) -> () {

        let hull = graphics::Mesh::new_polygon(
            ctx,
            graphics::DrawMode::fill(),
            &[Point2{x: 0.0, y: -15.0}, Point2{x: 9.0, y: 6.0}, Point2{x: -9.0, y: 6.0}],
            graphics::Color { r: 0.7, g: 0.7, b: 0.7, a: 1.0 }).unwrap();
        canvas.draw(&hull, self.param);
        let hull = graphics::Mesh::new_polygon(
            ctx,
            graphics::DrawMode::stroke(2.0),
            &[Point2{x: 0.0, y: -15.0}, Point2{x: 9.0, y: 6.0}, Point2{x: -9.0, y: 6.0}],
            graphics::Color::BLACK).unwrap();
        canvas.draw(&hull, self.param);

        let mut engine_color = graphics::Color { r: 0.7, g: 0.7, b: 0.7, a: 1.0 };
        if self.is_forced {
            engine_color = graphics::Color::RED;
            self.ps1.start_emit();
            self.ps2.start_emit();
        } else {
            self.ps1.stop_emit();
            self.ps2.stop_emit();
        };

        self.ps1.display(ctx, canvas);
        self.ps2.display(ctx, canvas);

        let engine1 = graphics::Mesh::new_rectangle(
            ctx,
            graphics::DrawMode::fill(),
            Rect::new(-7.0, 6.0, 5.0, 4.0),
            engine_color).unwrap();
        canvas.draw(&engine1, self.param);
        let engine1 = graphics::Mesh::new_rectangle(
            ctx,
            graphics::DrawMode::stroke(2.0),
            Rect::new(-7.0, 6.0, 5.0, 4.0),
            graphics::Color::BLACK).unwrap();
        canvas.draw(&engine1, self.param);

        let engine2 = graphics::Mesh::new_rectangle(
            ctx,
            graphics::DrawMode::fill(),
            Rect::new(2.0, 6.0, 5.0, 4.0),
            engine_color).unwrap();
        canvas.draw(&engine2, self.param);
        let engine2 = graphics::Mesh::new_rectangle(
            ctx,
            graphics::DrawMode::stroke(2.0),
            Rect::new(2.0, 6.0, 5.0, 4.0),
            graphics::Color::BLACK).unwrap();
        canvas.draw(&engine2, self.param);
    }
}